package fate.xp3;


import fate.ArchiveEntry;
import fate.ZlibUtils;

import java.io.IOException;
import java.io.RandomAccessFile;
import java.util.List;
import java.util.zip.DataFormatException;

public class XP3Entry implements ArchiveEntry {
    private final String path;
    private final boolean encrypted;
    private final long original_size;
    private final long compressed_size;
    private final String name;
    private final List<XP3Segment> segments;
    private final int adler;
    private final XP3Decrypter decrypter;

    public XP3Entry(String path, boolean encrypted, long original_size, long compressed_size, String name, List<XP3Segment> segments, int adler, XP3Decrypter decrypter) {
        this.path = path;
        this.encrypted = encrypted;
        this.original_size = original_size;
        this.compressed_size = compressed_size;
        this.name = name;
        this.segments = segments;
        this.adler = adler;
        this.decrypter = decrypter;
    }


    public boolean isEncrypted() {
        return encrypted;
    }

    public long getOriginalSize() {
        return original_size;
    }

    public long getCompressedSize() {
        return compressed_size;
    }

    public String getName() {
        return name;
    }

    public List<XP3Segment> getSegments() {
        return segments;
    }

    // TODO: callback decompress, stream, less buffer creation
    public byte[] read(RandomAccessFile file) throws IOException, DataFormatException {
        byte[] output = new byte[(int)original_size];
        long start = 0;
        for (XP3Segment segment: segments) {
            file.seek(segment.getOffset());
            byte[] buffer = new byte[(int)segment.getCompressedSize()];
            file.readFully(buffer);
            if (segment.isCompressed()) {
                buffer = ZlibUtils.uncompress(buffer, (int) segment.getOriginalSize());
                // TODO: check adler32
            }
            if (decrypter != null) {
                decrypter.decrypt(buffer, (int)start);
            }
            else if (encrypted) {
                throw new RuntimeException("XP3 is encrypted, but no decrypter provided.");
            }
            System.arraycopy(buffer, 0, output, (int)start, buffer.length);
            start += segment.getOriginalSize();
        }
        if (start != original_size) {
            throw new IOException("Incorrect uncompressed size");
        }
        return output;
    }

    public byte[] read() throws IOException {
        RandomAccessFile file = new RandomAccessFile(path, "r");
        try {
            return read(file);
        } catch (DataFormatException e) {
            throw new RuntimeException(e);
        } finally {
            file.close();
        }
    }

}
